<template>
  <div class="datetime-picker" :style="{ width: width }">
    <input
        type="text"
        :style="styleObj"
        :readonly="readonly"
        :disabled="disabled"
        v-model="showValue"
        @click="show = !show">
    <div class="picker-wrap" v-show="show">
      <table class="date-picker">
        <thead>
          <tr class="date-head">
            <th colspan="3">
              <span class="btn-prev" @click="yearClick(-1)">&lt;</span>
              <span class="show-year">{{now.getFullYear()}}</span>
              <span class="btn-next" @click="yearClick(1)">&gt;</span>
            </th>
            <th colspan="4">
              <span class="btn-prev" @click="monthClick(-1)">&lt;</span>
              <span class="show-month" :title="months.ch[now.getMonth()]">{{months.ch[now.getMonth()]}}</span>
              <span class="btn-next" @click="monthClick(1)">&gt;</span>
            </th>
          </tr>
          <tr class="date-days">
            <th v-for="day in days.ch">{{day}}</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="i in 5">
            <td v-for="j in 7"
                :class="date[i * 7 + j] && date[i * 7 + j].status"
                :date="date[i * 7 + j] && date[i * 7 + j].date"
                @click="pickDate(i * 7 + j)">{{date[i * 7 + j] && date[i * 7 + j].text}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      width: { type: String, default: '238px' },
      readonly: { type: Boolean, default: false },
      disabled: { type: Boolean, default: false },
      value: { type: String, default: '' },
      format: { type: String, default: 'YYYY-MM-DD' },
      styleObj: {type: Object, default: null}
    },
    data () {
      return {
        show: false,
        showValue: '',
        days: {
          en: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
          ch: ['日', '一', '二', '三', '四', '五', '六']
        },
        months: {
          en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          ch: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
        },
        date: [],
        now: new Date()
      };
    },
    watch: {
      now () {
        this.update();
      },
      show () {
        this.update();
      }
    },
    methods: {
      close () {
        this.show = false;
      },
      update () {
        var arr = [];
        var time = new Date(this.now);
        time.setMonth(time.getMonth(), 1);           // the first day
        var curFirstDay = time.getDay();
        curFirstDay === 0 && (curFirstDay = 7);
        time.setDate(0);                             // the last day
        var lastDayCount = time.getDate();
        for (let i = curFirstDay; i > 0; i--) {
          arr.push({
            text: lastDayCount - i + 1,
            time: new Date(time.getFullYear(), time.getMonth(), lastDayCount - i + 1),
            status: 'date-pass'
          });
        }
        time.setMonth(time.getMonth() + 2, 0);       // the last day of this month
        var curDayCount = time.getDate();
        time.setDate(1);                             // fix bug when month change
        var value = this.value || this.stringify(new Date());
        for (let i = 0; i < curDayCount; i++) {
          let tmpTime = new Date(time.getFullYear(), time.getMonth(), i + 1);
          let status = '';
          this.stringify(tmpTime) === value && (status = 'date-active');
          arr.push({
            text: i + 1,
            time: tmpTime,
            status: status
          });
        }
        var j = 1;
        while (arr.length < 42) {
          arr.push({
            text: j,
            time: new Date(time.getFullYear(), time.getMonth() + 1, j),
            status: 'date-future'
          });
          j++;
        }
        this.date = arr;
      },
      yearClick (flag) {
        this.now.setFullYear(this.now.getFullYear() + flag);
        this.now = new Date(this.now);
      },
      monthClick (flag) {
        this.now.setMonth(this.now.getMonth() + flag);
        this.now = new Date(this.now);
      },
      pickDate (index) {
        if (this.date[index]) {
          this.show = false;
          this.now = new Date(this.date[index].time);
          this.showValue = this.stringify();
          this.$emit('on-change', this.showValue);
        }
      },
      parse (str) {
        var time = new Date(str);
        return isNaN(time.getTime()) ? null : time;
      },
      stringify (time = this.now, format = this.format) {
        var year = time.getFullYear();
        var month = time.getMonth() + 1;
        var date = time.getDate();
        var monthName = this.months.ch[time.getMonth()];
        var map = {
          YYYY: year,
          MMM: monthName,
          MM: ('0' + month).slice(-2),
          M: month,
          DD: ('0' + date).slice(-2),
          D: date
        };
        return format.replace(/Y+|M+|D+/g, function (str) {
          return map[str];
        });
      },
      leave (e) {
        if (!this.$el.contains(e.target)) {
          this.close();
        }
      }
    },
    mounted () {
      this.now = this.parse(this.value) || new Date();
      document.addEventListener('click', this.leave, false);
    },
    beforeDestroy () {
      document.removeEventListener('click', this.leave, false);
    }
  };
</script>
<style scoped>
  .datetime-picker {
    position: relative;
    display: inline-block;
    font-family: "Segoe UI","Lucida Grande",Helvetica,Arial,"Microsoft YaHei";
    -webkit-font-smoothing: antialiased;
    color: #333;
  }
  .datetime-picker>[disabled]{
    cursor: not-allowed;
  }
  .datetime-picker * {
    box-sizing: border-box;
  }
  .datetime-picker input {
    width: 100%;
    padding: 5px 10px;
    height: 30px;
    outline: 0 none;
    border: 1px solid #ccc;
    font-size: 13px;
  }
  .datetime-picker .picker-wrap {
    position: absolute;
    z-index: 1000;
    width: 238px;
    height: 280px;
    margin-top: 2px;
    background-color: #fff;
    box-shadow: 0 0 6px #ccc;
  }
  .datetime-picker table {
    width: 100%;
    border-collapse: collapse;
    border-spacing: 0;
    text-align: center;
    font-size: 13px;
  }
  .datetime-picker tr {
    height: 34px;
    border: 0 none;
  }
  .datetime-picker th, .datetime-picker td {
    user-select: none;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0 none;
    line-height: 34px;
    text-align: center;
  }
  .datetime-picker td {
    cursor: pointer;
  }
  .datetime-picker td:hover {
    background-color: #f0f0f0;
  }
  .datetime-picker td.date-pass, .datetime-picker td.date-future {
    color: #aaa;
  }
  .datetime-picker td.date-active {
    background-color: #ececec;
    color: #3bb4f2;
  }
  .datetime-picker .date-head {
    background-color: #3bb4f2;
    text-align: center;
    color: #fff;
    font-size: 14px;
  }
  .datetime-picker .date-days {
    color: #3bb4f2;
    font-size: 14px;
  }
  .datetime-picker .show-year {
    display: inline-block;
    min-width: 50px;
    vertical-align: middle;
  }
  .datetime-picker .show-month {
    display: inline-block;
    width: 50px;
    vertical-align: middle;
  }
  .datetime-picker .btn-prev,
  .datetime-picker .btn-next {
    cursor: pointer;
    display: inline-block;
    padding: 0 5px;
    vertical-align: middle;
  }
  .datetime-picker .btn-prev:hover,
  .datetime-picker .btn-next:hover {
    background: rgba(16, 160, 234, 0.5);
  }
</style>

